﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Common;
using ImageProcessing.Detectors;
using System.Drawing;
using ImageProcessing.Storage;
using PixelFormat = System.Windows.Media.PixelFormat;

namespace ImageProcessing.Common
{
    public static class HelperMethods
    {
        public const string RawFileExtension = ".raw";

        public static string GetImageFileNamePath(string image)
        {
            return Path.Combine(GetImagePath(), image);
        }

        public static string GetImagePath()
        {
            return Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"..\", @"Images\"));
        }

        public static void SaveImageToJpeg(TagInfo tagInfo, PixelFormat pixelFormat, int width, int height, byte[] rawImageData)
        {
            const double dpi = 96;

            BitmapSource bmpSource = BitmapSource.Create(width, height, dpi, dpi, pixelFormat, null, rawImageData, width);

            var fileName = GetImageFileNamePath(tagInfo.TagId.ToString() + "-" + pixelFormat.ToString() + ".jpg");

            using (Stream fs = new FileStream(fileName, FileMode.OpenOrCreate))
            {
                var pbe = new JpegBitmapEncoder();
                BitmapMetadata metaData = new BitmapMetadata("jpg")
                                              {
                                                  ApplicationName = "wp7ort",
                                                  Keywords = new ReadOnlyCollection<string>(new List<string>() { tagInfo.TagId.ToString(), tagInfo.TagName })
                                              };
                BitmapFrame frame = BitmapFrame.Create(bmpSource, null, metaData, null);

                pbe.Frames.Add(frame);
                pbe.Save(fs);
                fs.Flush();
            }
        }
        public static int[] LoadARGBImage(string imageFileName, PixelFormat pixelFormat, int? targetWidth = null, int? targetHeight = null)
        {
            var writeableBitmap = LoadImage(imageFileName, pixelFormat, targetWidth, targetHeight);

            var width = writeableBitmap.PixelWidth;
            var height = writeableBitmap.PixelHeight;

            var argb = new int[width * height];

            writeableBitmap.CopyPixels(argb, writeableBitmap.BackBufferStride, 0);

            return argb;
        }

        private static WriteableBitmap LoadRawImage(string imageFileName, int? targetWidth = null, int? targetHeight = null)
        {
            const double dpi = 96;
            WriteableBitmap writeableBitmap = null;

            if (imageFileName.Contains(RawFileExtension))
            {
                OnlineImageArchiver onlineImageArchiver = new OnlineImageArchiver();
                LoadedImage loadedImage = onlineImageArchiver.LoadRawImage(imageFileName);

                var bmpSource = BitmapSource.Create(loadedImage.width, loadedImage.height, dpi, dpi, PixelFormats.Gray8, null, loadedImage.rawImage, loadedImage.width);

                writeableBitmap = new WriteableBitmap(bmpSource);
            }
            else
            {
                writeableBitmap = LoadOrigSizeImage(imageFileName, PixelFormats.Gray8);
            }

            return ResizeImage(writeableBitmap, targetWidth, targetHeight);
        }

        public static WriteableBitmap LoadOrigSizeImage(string imageFileName, PixelFormat pixelFormat)
        {
            BitmapImage bmImage;
            try
            {
                bmImage = new BitmapImage(new Uri(imageFileName, UriKind.RelativeOrAbsolute));
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                throw;
            }

            var bgra = new FormatConvertedBitmap(bmImage, pixelFormat, null, 0);

            return new WriteableBitmap(bgra);
        }

        public static WriteableBitmap LoadImage(string imageFileName, PixelFormat pixelFormat, int? targetWidth = null, int? targetHeight = null)
        {
            if (pixelFormat == PixelFormats.Gray8)
                return LoadRawImage(imageFileName, targetWidth, targetHeight);


            return ResizeImage(LoadOrigSizeImage(imageFileName, pixelFormat), targetWidth, targetHeight);
        }

        public static WriteableBitmap ResizeImage(WriteableBitmap writeableBitmap, int? targetWidth = null, int? targetHeight = null)
        {
            if (targetWidth.HasValue && targetHeight.HasValue)
                if (writeableBitmap.PixelWidth != targetWidth || writeableBitmap.PixelHeight != targetHeight)
                {
                    var switchWidthHeight = targetWidth > targetHeight && writeableBitmap.PixelHeight > writeableBitmap.PixelWidth;

                    if (switchWidthHeight)
                    {
                        var tempW = targetWidth;
                        var tempH = targetHeight;

                        targetHeight = tempW;
                        targetWidth = tempH;
                    }
                    writeableBitmap = writeableBitmap.Resize(targetWidth.Value, targetHeight.Value);
                }

            return writeableBitmap;
        }

        /// <summary>
        /// Build from http://www.w3.org/Graphics/JPEG/jfif.txt info
        /// </summary>
        /// <param name="imageFileName"></param>
        /// <param name="targetWidth"> </param>
        /// <param name="targetHeight"> </param>
        /// <returns></returns>
        public static LoadedImage LoadYImage(string imageFileName, int? targetWidth = null, int? targetHeight = null)
        {
            if (imageFileName.Contains(".raw"))
            {
                OnlineImageArchiver OnlineImageArchiver = new OnlineImageArchiver();
                LoadedImage loadedImage = OnlineImageArchiver.LoadRawImage(imageFileName);

                if (targetWidth.HasValue && targetWidth.Value != loadedImage.width || targetHeight.HasValue && targetHeight.Value != loadedImage.height)
                    throw new Exception("width and height problem..... to fix");

                return loadedImage;
            }

            var argbImage = LoadARGBImage(imageFileName, PixelFormats.Gray8, targetWidth, targetHeight);

            var yImage = new byte[argbImage.Length];

            for (var i = 0; i < argbImage.Length; i++)
            {
                var argbPixel = argbImage[i];

                var argb = BitConverter.GetBytes(argbPixel);
                var a = argb[3];
                var r = argb[2];
                var g = argb[1];
                var b = argb[0];

                var y = 0.299 * r + 0.587 * g + 0.114 * b;

                yImage[i] = (byte)y;
            }

            return new LoadedImage() { rawImage = yImage };
        }

        public static List<InterestPoint> GetPoints(string imageName, IInterestPointDetector ipd, int? targetWidth = null, int? targetHeight = null)
        {
            var argbFrame = LoadARGBImage(imageName, PixelFormats.Pbgra32, targetWidth, targetHeight);
            return ipd.GetInterestPoints(ref argbFrame);
        }

        public static void GetImageDimensions(string imageName, out int width, out int height)
        {
            var image = new Bitmap(imageName);
            width = image.Width;
            height = image.Height;
            image.Dispose();
        }
    }

}
